﻿using System;
using System.Runtime.Serialization;

using SharpGL.SceneGraph.Assets;

namespace SharpGL.SceneGraph.Primitives
{
    /// <summary>
    /// The axies objects are design time rendered primitives
    /// that show an RGB axies at the origin of the scene.
    /// </summary>
    [DataContract(IsReference = true)]
    public class Axies : ContextualSceneElement, IRenderable
    {
        #region Private Fields

        /// <summary>
        /// The internal display list.
        /// </summary>
        private DisplayList displayList = null;

        #endregion Private Fields

        #region Protected Methods

        protected override void OnCreateInContext(OpenGL gl)
        {
            //  Init display list object. 
            displayList = new DisplayList();

            //  Create the display list 
            displayList.Create(gl);

            //  Begin the display list.
            displayList.Begin(DisplayList.DisplayListMode.Compile);

            //  Render.
            InternalRender(gl);

            //  End the display list.
            displayList.End();
        }

        protected override void OnDestroyInContext(OpenGL gl)
        {
            if (displayList != null)
            {
                displayList.Destroy();
                displayList = null;
            }
        }
        
        /// <summary>
        /// Simple render to the provided instance of OpenGL.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        protected void InternalRender(OpenGL gl)
        {
            if (OpenGL.IsValidContext(gl))
            {
                //  Push all attributes, disable lighting and depth testing.
                gl.PushAttrib(OpenGL.GL_CURRENT_BIT | OpenGL.GL_ENABLE_BIT |
                    OpenGL.GL_LINE_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
                gl.Disable(OpenGL.GL_LIGHTING);
                gl.Disable(OpenGL.GL_TEXTURE_2D);
                gl.DepthFunc(OpenGL.GL_ALWAYS);

                //  Set a nice fat line width.
                gl.LineWidth(1.50f);

                //  Draw the axies.
                gl.Begin(OpenGL.GL_LINES);
                gl.Color(1f, 0f, 0f, 1f);
                gl.Vertex(0, 0, 0);
                gl.Vertex(1, 0, 0);
                gl.Color(0f, 1f, 0f, 1f);
                gl.Vertex(0, 0, 0);
                gl.Vertex(0, 1, 0);
                gl.Color(0f, 0f, 1f, 1f);
                gl.Vertex(0, 0, 0);
                gl.Vertex(0, 0, 1);
                gl.End();

                //  Restore attributes.
                gl.PopAttrib();
            }
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Axies"/> class.
        /// </summary>
        public Axies()
        {
            Name = "Design Time Axies";
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Render to the provided instance of OpenGL.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="renderMode">The render mode.</param>
        public void Render(OpenGL gl, RenderMode renderMode)
        {
            //  If we do not have the display list, we must create it.
            //  Otherwise, we can simple call the display list.
            if (displayList == null)
                InternalRender(gl);
            else
            {
                ValidateRenderingContext(gl);

                displayList.Call();
            }
        }

        #endregion Public Methods
    }
}
